import { Button, Canvas, Component, EventHandler, EventTouch, Node, SpriteFrame, _decorator, warn } from "cc";
import GlobalDC from "../common/data.global.center";

const {ccclass, property} = _decorator;

@ccclass
export class UI extends Component{

    /** 获取节点深度 */
    public static getDepth(node: Node){
        let d: number;
        if(node.getComponent(Canvas)) d = 0;
        else d = this.getDepth(node.parent) + 1;
        return d;
    }
    /** 节点层级深度 */
    protected get depth(){
        return UI.getDepth(this.node);
    }
    /** 组件名称 */
    get comp_name(){
		let reg = new RegExp('(?<=<)(?<comp_name>[\\w, \\W]+)(?=>)', 'g');
        return reg.exec(this.name).groups.comp_name;
    }

    /** 给按钮绑定点击事件 */
    private __ButtonBindCall(){
        this.__handle = mtec.cc.creatEventHandle({
            target: this.node,
            component: this.comp_name,
            handler: '__ClickButton',
        });

        this.node.getComponentsInChildren(Button)
        .filter(btn=>{
            let pass = false;
            // 如果btn的事件列表是空的，则直接无脑把自己的中继事件放进去
            if(btn.clickEvents.length===0) pass = true;
            else{
                // 分别收集手动绑定事件和自动绑定事件
                let [hand_event, auto_event] = [[], []] as EventHandler[][];
                btn.clickEvents.forEach(hdl=>{
                    if(hdl.handler==='__ClickButton') auto_event.push(hdl);
                    else hand_event.push(hdl);
                });

                // 如果脚本中初始化了按钮事件，并且按钮事件列表中没有其它初始化事件，则直接添加
                if(auto_event.length===0 && this._click_event_[btn.node.name]) pass = true;
                // 如果存在其它初始化事件，则以组件的深度优先（即距离按钮最近的组件为准）覆盖，相同深度则以当前为准覆盖
                else if(auto_event.length > 0){
                    let power = this.depth;
                    if(this._click_event_[btn.node.name]) power += 10000;

                    let el = auto_event.map(h=>{
                        let comp = h.target.getComponent(UI);
                        let p = comp.depth;
                        if(comp._click_event_[btn.node.name]) p += 10000;
                        return {h, p};
                    }).sort((a, b)=>a.p-b.p).pop();

                    if(el.p <= power) pass = true;
                    else auto_event.splice(auto_event.indexOf(el.h), 1);

                    auto_event.forEach(h=>btn.clickEvents.splice(btn.clickEvents.indexOf(h), 1));
                }
            }

            return pass;
        }).forEach(btn=>{
            btn.clickEvents.push(this.__handle);
            this.__btn_map__.set(btn.node.name, btn);
        });
    }

    /** 按钮点击事件中继 */
    protected __ClickButton(event: EventTouch){
		let node = event.currentTarget as Node;

		let btn = node.getComponent(Button);
		if(node.name in this._click_event_){
			Reflect.apply(Reflect.get(this._click_event_, node.name), this, [btn]);

			// 发送点击事件,只对初始化的按钮发送事件
			GlobalDC.Trigger.CLICK = {
				component: this.comp_name,
				button: node.name
			};
		}else this.ClickBtn(btn);
    }

    /** 没有被初始化的按钮 */
    protected ClickBtn(btn: Button){
		btn.interactable
        warn(`<${this.comp_name}> 按钮[${btn.node.name}]未被初始化`);
    }

	/** ui交互控制 */
	protected interactable(able: boolean){
		this.__btn_map__.forEach(btn=>btn.interactable = able);
	}

    /** 初始化组件基本逻辑 */
    private __init(){
        if(!this._click_event_.__common) this._click_event_.__common = (()=>{}).bind(this);
        this.__ButtonBindCall();
        if(this.sframe.length>0){
            this.sframe.forEach(frame=>this.smap.set(frame.name, frame));
            this.sframe = undefined;
        }
		if(this.initAfterOnLoad) this.initAfterOnLoad();
    }

    /** 组件事件对象 */
    protected _click_event_: {[name: string]: (this: UI, button: Button)=>void} = {};
    /** 组件上的按钮通用回调 */
    protected __handle: EventHandler = null;
    protected __btn_map__: Map<string, Button> = new Map();
    /** ui常用贴图映射 */
    protected smap: Map<string, SpriteFrame> = new Map();

    /** 在加载后的一些自定义初始化 */
    protected initAfterOnLoad(): void{

	};

    @property([SpriteFrame])
    /** ui常用贴图 */
    private sframe: SpriteFrame[] = [];

    protected onLoad(){
        this.__init();
    }
}